using System;
using System.Collections.Generic;

namespace Fadd.Data.Mappings
{
    /// <summary>
    /// Default mapping implementation
    /// </summary>
    public class Mapping : IMapping
    {
        private readonly string _tableName;
        private readonly Type _type;
        private readonly Dictionary<string, PropertyMapping> _properties = new Dictionary<string, PropertyMapping>();
        private readonly List<PropertyMapping> _primaryKeys = new List<PropertyMapping>();

        /// <summary>
        /// Initializes a new instance of the <see cref="Mapping"/> class.
        /// </summary>
        /// <param name="type">Type that the mapping is for.</param>
        /// <param name="tableName">Name of the database table.</param>
        public Mapping(Type type, string tableName)
        {
            Check.Require(type, "type");
            Check.NotEmpty(tableName, "tableName");

            _tableName = tableName;
            _type = type;
        }

        /// <summary>
        /// Name of database table.
        /// </summary>
        public string TableName
        {
            get { return _tableName; }
        }

        /// <summary>
        /// Type that the mapping is for.
        /// </summary>
        public Type Type
        {
            get { return _type; }
        }

        /// <summary>
        /// Gets all properties
        /// </summary>
        public IEnumerable<PropertyMapping> Properties
        {
            get { return _properties.Values; }
        }

        /// <summary>
        /// Gets all primary keys
        /// </summary>
        public IList<PropertyMapping> PrimaryKeys
        {
            get 
            {
                if (_primaryKeys.Count == 0)
                    FindPrimaryKeys();
                return _primaryKeys.AsReadOnly();
            }
        }

        /// <summary>
        /// Get a column name from a property name.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string GetColumnName(string name)
        {
            PropertyMapping mapping;
            return _properties.TryGetValue(name, out mapping) ? mapping.ColumnName : null;
        }

		

        /// <summary>
        /// Gets current primary key.
        /// </summary>
        /// <returns>The primary key if exactly ONE is defined; otherwise null.</returns>
        public PropertyMapping GetPrimaryKey()
        {
            if (_primaryKeys.Count == 0)
                FindPrimaryKeys();

            return _primaryKeys.Count == 1 ? _primaryKeys[0] : null;
        }

        private void FindPrimaryKeys()
        {
            foreach (KeyValuePair<string, PropertyMapping> pair in _properties)
            {
                if (pair.Value.IsPrimaryKey)
                    _primaryKeys.Add(pair.Value);
            }
        }

        /// <summary>
        /// Add a property mapping
        /// </summary>
        /// <param name="propertyName">Class property</param>
        /// <param name="columnName">Table column</param>
        public void Add(string propertyName, string columnName)
        {
            _properties.Add(propertyName, new PropertyMapping(propertyName, columnName));
        }

        /// <summary>
        /// Add a property mapping
        /// </summary>
        /// <param name="propertyName">Class property</param>
        /// <param name="columnName">Table column</param>
        /// <param name="isPrimaryKey">True if property is a primary key.</param>
        /// <param name="generatorType">Type of generator used.</param>
        public void Add(string propertyName, string columnName, bool isPrimaryKey, string generatorType)
        {
            PropertyMapping mapping = new PropertyMapping(propertyName, columnName);
            mapping.IsPrimaryKey = isPrimaryKey;
            if (mapping.IsPrimaryKey)
                mapping.Generator = generatorType;
            _properties.Add(propertyName, mapping);
            if (isPrimaryKey)
                _primaryKeys.Add(mapping);
        }
    }
}
